using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Reflection;
using MonPocGarage.ArmyContracts.Common.Enums;
using MonPocGarage.Common.Logging;

namespace MonPocGarage.ArmyContracts
{
    public class Army : INotifyPropertyChanged 
    {
        #region *** CONSTRUCTORS ***

        public Army()
        {
            m_ArmyMonsters = new ObservableCollection<Monster>();
            m_ArmyUnits = new ObservableCollection<Unit>();
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        public Army(Monster monster)
        {
            m_ArmyMonsters = new ObservableCollection<Monster>
                                 {
                                     (Monster)monster.Clone()
                                 };
            m_ArmyUnits = new ObservableCollection<Unit>();
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        public Army(List<Monster> monsters)
        {
            m_ArmyMonsters = new ObservableCollection<Monster>();
            foreach (Monster monster in monsters)
            {
                m_ArmyMonsters.Add((Monster)monster.Clone());
            }
            
            m_ArmyUnits = new ObservableCollection<Unit>();
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        public Army(Unit unit)
        {
            m_ArmyMonsters = new ObservableCollection<Monster>();
            m_ArmyUnits = new ObservableCollection<Unit>
                              {
                                  (Unit)unit.Clone()
                              };
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        public Army(List<Unit> units)
        {
            m_ArmyMonsters = new ObservableCollection<Monster>();
            m_ArmyUnits = new ObservableCollection<Unit>();
            foreach (Unit unit in units)
            {
                m_ArmyUnits.Add((Unit)unit.Clone());
            }
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        public Army(Monster monster, Unit unit)
        {
            m_ArmyMonsters = new ObservableCollection<Monster>
                                 {
                                     (Monster)monster.Clone()
                                 };
            m_ArmyUnits = new ObservableCollection<Unit>
                              {
                                  (Unit)unit.Clone()
                              };
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        public Army(Monster monster, List<Unit> units)
        {
            m_ArmyMonsters = new ObservableCollection<Monster>
                                 {
                                     (Monster)monster.Clone()
                                 };
            m_ArmyUnits = new ObservableCollection<Unit>();
            foreach (Unit unit in units)
            {
                m_ArmyUnits.Add((Unit)unit.Clone());
            }
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        public Army(List<Monster> monsters, Unit unit)
        {
            m_ArmyMonsters = new ObservableCollection<Monster>();
            foreach (Monster monster in monsters)
            {
                m_ArmyMonsters.Add((Monster)monster.Clone());
            }
            m_ArmyUnits = new ObservableCollection<Unit>
                              {
                                  (Unit)unit.Clone()
                              };
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        public Army(List<Monster> monsters, List<Unit> units)
        {
            m_ArmyMonsters = new ObservableCollection<Monster>();
            foreach (Monster monster in monsters)
            {
                m_ArmyMonsters.Add((Monster)monster.Clone());
            }
            m_ArmyUnits = new ObservableCollection<Unit>();
            foreach (Unit unit in units)
            {
                m_ArmyUnits.Add((Unit)unit.Clone());
            }
            m_ArmyBuildings = new ObservableCollection<Building>();
        }

        #endregion

        #region *** COLLECTION PROPERTIES ***

        private readonly ObservableCollection<Monster> m_ArmyMonsters;
        private readonly ObservableCollection<Unit> m_ArmyUnits;
        private readonly ObservableCollection<Building> m_ArmyBuildings = new ObservableCollection<Building>();

        public ObservableCollection<Monster> ArmyMonsters
        {
            get { return m_ArmyMonsters; }
        }

        public ObservableCollection<Unit> ArmyUnits
        {
            get { return m_ArmyUnits; }
        }

        public ObservableCollection<Building> ArmyBuildings
        {
            get { return m_ArmyBuildings; }
        }

        #endregion        

        public string ArmyName { get; private set; }

        public Faction ArmyFaction { get; private set; }

        public bool IsValidArmy()
        {
            return true;
        }

        #region *** ADD / REMOVE METHODS ***

        public bool AddUnit(Unit unit)
        {
            bool success;
            try
            {
                if (m_ArmyUnits.Count < 15)
                {
                    m_ArmyUnits.Add((Unit)unit.Clone());
                    success = true;
                    OnPropertyChanged("ArmyUnits");
                }
                else
                {
                    success = false;
                }
            }
            catch (Exception ex)
            {
                string logMessage = string.Format("{0}:{1} - Unit:{2}",
                                                  MethodBase.GetCurrentMethod().DeclaringType.FullName,
                                                  MethodBase.GetCurrentMethod().Name,
                                                  unit.UnitName);
                LogHandler.LogException(logMessage, ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        public bool RemoveUnit(Unit unit)
        {
            bool success;
            try
            {
                if (m_ArmyUnits.Contains(unit))
                {
                    m_ArmyUnits.Remove(unit);
                    success = true;
                    OnPropertyChanged("ArmyUnits");
                }
                else
                {
                    success = false;
                }
            }
            catch (Exception ex)
            {
                string logMessage = string.Format("{0}:{1} - Unit:{2}",
                                                  MethodBase.GetCurrentMethod().DeclaringType.FullName,
                                                  MethodBase.GetCurrentMethod().Name,
                                                  unit.UnitName);
                LogHandler.LogException(logMessage, ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        public bool AddMonster(Monster monster)
        {
            bool success;
            try
            {
                m_ArmyMonsters.Add((Monster)monster.Clone());
                success = true;
                OnPropertyChanged("ArmyMonsters");
            }
            catch (Exception ex)
            {
                string logMessage = string.Format("{0}:{1} - Faction:{2}",
                                                  MethodBase.GetCurrentMethod().DeclaringType.FullName,
                                                  MethodBase.GetCurrentMethod().Name,
                                                  monster.MonsterName);
                LogHandler.LogException(logMessage, ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        public bool RemoveMonster(Monster monster)
        {
            bool success;
            try
            {
                if (m_ArmyMonsters.Contains(monster))
                {
                    m_ArmyMonsters.Remove(monster);
                    success = true;
                    OnPropertyChanged("ArmyMonsters");
                }
                else
                {
                    success = false;
                }
            }
            catch (Exception ex)
            {
                string logMessage = string.Format("{0}:{1} - Monster:{2}",
                                                  MethodBase.GetCurrentMethod().DeclaringType.FullName,
                                                  MethodBase.GetCurrentMethod().Name,
                                                  monster.MonsterName);
                LogHandler.LogException(logMessage, ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        public bool AddBuilding(Building building)
        {
            bool success;
            try
            {
                m_ArmyBuildings.Add((Building)building.Clone());
                success = true;
                OnPropertyChanged("ArmyBuildings");
            }
            catch (Exception ex)
            {
                string logMessage = string.Format("{0}:{1} - Building:{2}",
                                                  MethodBase.GetCurrentMethod().DeclaringType.FullName,
                                                  MethodBase.GetCurrentMethod().Name,
                                                  building.BuildingName);
                LogHandler.LogException(logMessage, ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        public bool RemoveBuilding(Building building)
        {
            bool success;
            try
            {
                if (m_ArmyBuildings.Contains(building))
                {
                    m_ArmyBuildings.Remove(building);
                    success = true;
                    OnPropertyChanged("ArmyBuildings");
                }
                else
                {
                    success = false;
                }
            }
            catch (Exception ex)
            {
                string logMessage = string.Format("{0}:{1} - Building:{2}",
                                                  MethodBase.GetCurrentMethod().DeclaringType.FullName,
                                                  MethodBase.GetCurrentMethod().Name,
                                                  building.BuildingName);
                LogHandler.LogException(logMessage, ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        public bool ChangeArmyFaction(Faction newFaction)
        {
            bool success;
            try
            {
                m_ArmyUnits.Clear();
                OnPropertyChanged("ArmyUnits");
                m_ArmyMonsters.Clear();
                OnPropertyChanged("ArmyMonsters");
                m_ArmyBuildings.Clear();
                OnPropertyChanged("ArmyBuildings");
                ArmyFaction = newFaction;
                OnPropertyChanged("ArmyFaction");
                success = true;
            }
            catch (Exception ex)
            {
                string logMessage = string.Format("{0}:{1} - Faction:{2}",
                                                  MethodBase.GetCurrentMethod().DeclaringType.FullName,
                                                  MethodBase.GetCurrentMethod().Name,
                                                  newFaction);
                LogHandler.LogException(logMessage, ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        public bool ChangeArmyName(string newName)
        {
            ArmyName = newName;
            OnPropertyChanged("ArmyName");
            return true;
        }

        #endregion

        #region *** INotifyPropertyChanged Implementation ***

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);
                PropertyChanged(this, args);
            }

        }

        #endregion        

    }
}